﻿using System;

namespace MouseAndCat.Model
{
    public enum Event : byte
    {
        None = 0,
        MouseEnter = 1,
        MouseLeave = 2,
        MouseMove = 3,
        MouseDown = 4,
        MouseUp = 5,
        LeftMouseDoubleClick = 6,
        RightMouseDown = 7,
        RightMouseUp = 8,
        MouseWheel = 9,
        KeyUp = 10,
        KeyDown = 11
    }

    public struct Message
    {
        private const int sz_timestamp = sizeof(uint);
        private const int sz_short = sizeof(short);
        private const int sz_event = sizeof(Event);

        private const int sz_keyboard = sz_timestamp + sz_event + (sizeof(byte) * 2);
        private const int sz_mouse =    sz_timestamp + sz_event + (sz_short * 2);
        private const int sz_switch =   sz_timestamp + sz_event + (sz_short * 2);
        
        public uint TimeStamp;
        public Event Type;
        public short X;
        public short Y;
        public short WheelDelta;
        public byte Modifier;
        public byte Key;

        public byte[] Bytes
        {
            get
            {
                int length;
                byte[] payload;

                switch (Type)
                {
                    case Event.KeyDown:
                    case Event.KeyUp:

                        length = sz_keyboard;
                        payload = new byte[] { Key };
                        break;

                    case Event.MouseEnter:
                    case Event.MouseLeave:

                        length = sz_switch;
                        payload = GetXY(X, Y);
                        break;

                    case Event.RightMouseDown:
                    case Event.RightMouseUp:
                    case Event.MouseDown:
                    case Event.MouseMove:
                    case Event.MouseUp:
                    case Event.LeftMouseDoubleClick:

                        length = sz_mouse;
                        payload = GetXY(X, Y);
                        break;

                    case Event.MouseWheel:

                        length = sz_mouse;
                        payload = GetXY(0, WheelDelta);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("Unrecognized message type: " + Type);
                }

                byte[] bytes = new byte[length];
                byte[] timestamp = BitConverter.GetBytes(TimeStamp);
                Array.Copy(timestamp, bytes, sz_timestamp);
                int index = sz_timestamp;
                bytes[index++] = (byte)Type;

                if(payload != null)
                    Array.Copy(payload, 0, bytes, index, payload.Length);

                return bytes;
            }
        }

        private byte[] GetXY(short x, short y)
        {
            byte[] coordinates = new byte[sz_short * 2];
            Array.Copy(BitConverter.GetBytes(x), coordinates, sz_short);
            Array.Copy(BitConverter.GetBytes(y), 0, coordinates, sz_short, sz_short);
            return coordinates;
        }

        public override string ToString()
        {
            return String.Format("{1}: {2}, {3}; @{0}", TimeStamp, Type, X, Y);
        }
    }
}
